use serde::{Deserialize, Serialize};
use std::fs;
use std::path::Path;
use std::io::Read;
use docx_rs::*;
use regex::Regex;

#[derive(Debug, Serialize, Deserialize)]
struct Data {
    name: String,
    scan_path: String,
    exp_path: String,
    scan_type: String,
    gen_page: i32,
}

// Learn more about Tauri commands at https://tauri.app/develop/calling-rust/
#[tauri::command]
fn greet(name: &str) -> String {
    format!("Hello, {}! You've been greeted from Rust!", name)
}

#[tauri::command]
fn code_extranction(data: Data) -> Result<String, String> {
    // 创建一个新的 Word 文档
    let mut doc = Docx::new();
    let mut content = String::new();
    
    let char_limit = data.gen_page as usize * 2000;
    
    match visit_dirs(Path::new(&data.scan_path), &data.scan_type, &mut content, char_limit) {
        Ok(reached_limit) => {
            if reached_limit {
                println!("已达到指定页数限制");
            }
        },
        Err(e) => return Err(format!("遍历目录失败: {}", e)),
    }
    
    // 将内容按行分割，为每行创建一个新的段落
    for line in content.lines() {
        doc = doc.add_paragraph(
            Paragraph::new()
                .add_run(
                    Run::new()
                        .add_text(line)
                        .size(20) // 设置字体大小
                )
        );
    }
    
    // 保存文档
    let path = format!("{}/{}.docx", data.exp_path,data.name);
    let file = std::fs::File::create(&path).map_err(|e| format!("创建文件失败: {}", e))?;
    match doc.build().pack(file) {
        Ok(_) => Ok("文档生成成功！".to_string()),
        Err(e) => Err(format!("生成文档失败: {}", e)),
    }
}

// 修改遍历目录的函数，添加字符限制
fn visit_dirs(dir: &Path, file_type: &str, content: &mut String, char_limit: usize) -> std::io::Result<bool> {
    if dir.is_dir() {
        for entry in fs::read_dir(dir)? {
            let entry = entry?;
            let path = entry.path();
            
            if content.len() >= char_limit {
                return Ok(true); // 已达到限制
            }
            
            if path.is_dir() {
                if visit_dirs(&path, file_type, content, char_limit)? {
                    return Ok(true); // 在子目录中达到限制
                }
            } else {
                if let Some(ext) = path.extension() {
                    if ext == file_type {
                        if process_file(&path, content, char_limit)? {
                            return Ok(true); // 处理文件时达到限制
                        }
                    }
                }
            }
        }
    }
    Ok(false)
}

// 修改处理单个文件的函数
fn process_file(file_path: &Path, content: &mut String, char_limit: usize) -> std::io::Result<bool> {
    let mut file = fs::File::open(file_path)?;
    let mut file_content = String::new();
    file.read_to_string(&mut file_content)?;
    
    // 处理代码内容（移除注释和空行）
    let processed_content = remove_comments_and_empty_lines(&file_content);
    
    // 计算新内容后的总长度
    let new_content = format!(
        "{}\n",
        processed_content
    );
    
    // 检查是否会超出限制
    if content.len() + new_content.len() > char_limit {
        let remaining = char_limit.saturating_sub(content.len());
        if remaining > 0 {
            content.push_str(&new_content[..remaining]);
        }
        return Ok(true);
    }
    
    content.push_str(&new_content);
    Ok(false)
}

// 修改移除注释和空行的函数，保持代码缩进
fn remove_comments_and_empty_lines(code: &str) -> String {
    // 移除多行注释
    let multi_line_comment = Regex::new(r"/\*[\s\S]*?\*/").unwrap();
    // 移除单行注释
    let single_line_comment = Regex::new(r"//.*").unwrap();
    // 移除尖括号
    let angele_bracket = Regex::new(r"<!--[\s\S]*?-->").unwrap();
    
    let mut result = multi_line_comment.replace_all(code, "").to_string();
    result = single_line_comment.replace_all(&result, "").to_string();
    result = angele_bracket.replace_all(&result, "").to_string();
    
    // 移除空行但保持缩进
    result.lines()
        .filter(|line| !line.trim().is_empty() && !line.starts_with("//") && !line.trim().len() >= 1)
        .map(|line| line.to_string())  // 保持原始缩进
        .collect::<Vec<String>>()
        .join("\n")
}

#[cfg_attr(mobile, tauri::mobile_entry_point)]
pub fn run() {
    tauri::Builder::default()
        .plugin(tauri_plugin_fs::init())
        .plugin(tauri_plugin_dialog::init())
        .plugin(tauri_plugin_opener::init())
        .invoke_handler(tauri::generate_handler![greet, code_extranction])
        .run(tauri::generate_context!())
        .expect("error while running tauri application");
}
